package com.zyf.utils;

import org.opencv.core.*;
import org.opencv.core.Point;
import org.opencv.highgui.HighGui;
import org.opencv.imgproc.Imgproc;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.BufferedImageFilter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;

import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

import org.opencv.core.Mat;
import org.opencv.imgcodecs.Imgcodecs;

import javax.imageio.ImageIO;
import javax.swing.JLabel;

import static org.opencv.imgproc.Imgproc.Sobel;
import static org.opencv.imgproc.Imgproc.cvtColor;

/**
 * 类名称：ImageUtil
 * 类描述：   图片操作工具类    	把图片加载到内存，给图片 贴图，给图片添加文字
 * 创建时间：2021年7月30日 上午10:27:13
 * <p>
 * <p>
 * <p>
 * 2、opencv.highgui.Highgui包中的类imread, imwrite,等都移到import org.opencv.imgcodecs.Imgcodecs里面。
 * <p>
 * 3、只需导入import org.opencv.imgcodecs.Imgcodecs；然后把Mat image = Highgui.imread（“”）改为Mat image = Imgcodecs.imread（“”），就OK啦。
 */
public class ImageUtils {


    /**
     * 解析本地图片或者http网络图片，并把图片加载到缓冲区
     *
     * @param path 图片路径（本地路径或者网络图片http访问路径）
     * @throws IOException 抛出异常
     */
    public static BufferedImage imageIoRead(String path) throws IOException {
        BufferedImage bufferedImage;
        if (path.contains("http")) {
            //网络图片
            bufferedImage = ImageIO.read(new URL(path));
        } else {
            //本地图片
            bufferedImage = ImageIO.read(new File(path));
        }
        return bufferedImage;
    }

    /**
     * 给一张图片贴 图片，并生成新图片
     *
     * @param bigPath     底图路径
     * @param smallPath   要贴的图片路径
     * @param outPath     合成输出图片路径
     * @param x           贴图的位置
     * @param y           贴图的位置
     * @param smallWidth  要贴的图片宽度
     * @param smallHeight 要贴的图片高度
     * @throws IOException 抛出io异常
     */
    public static void mergeImage(String bigPath,
                                  String smallPath,
                                  String outPath,
                                  String x,
                                  String y,
                                  int smallWidth,
                                  int smallHeight) throws IOException {
        try {
            //加载图片
            BufferedImage small = imageIoRead(smallPath);
            BufferedImage big = imageIoRead(bigPath);
            //得到2d画笔对象
            Graphics2D g = big.createGraphics();
            float fx = Float.parseFloat(x);
            float fy = Float.parseFloat(y);
            int x_i = (int) fx;
            int y_i = (int) fy;
            g.drawImage(small, x_i, y_i, smallWidth, smallHeight, null);
            g.dispose();
            //输出图片
            ImageIO.write(big, "png", new File(outPath));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 向画布上写多行文字文字，自动居中
     *
     * @param filePath   原图路径
     * @param text       要添加的文字
     * @param outPath    输出图片路径
     * @param font       字体
     * @param textHeight          坐标y
     * @param color      字体颜色
     * @param fontheight 字体高度
     * @param maxWeight  每行字体最大宽度
     * @param center     是否居中
     * @param rate       字体间距
     * @return int  写了几行字
     */
    public static int drawTextInImg(String filePath,
                                    String text,
                                    String outPath,
                                    Font font,
                                    int textHeight,
                                    Color color,
                                    int maxWeight,
                                    int fontheight,
                                    boolean center,
                                    double rate) {
        int row = 0;
        try {
            //图片加载到缓冲区
            BufferedImage bimage = imageIoRead(filePath);
            //图片的高
            int imgHerght = bimage.getHeight();
            //图片的宽
            int imgWidth = bimage.getWidth();
            //居中显示
            int x = (imgWidth - maxWeight) / 2;
            int y=textHeight;
            //得到2d画笔对象
            Graphics2D g = bimage.createGraphics();
            //设置填充颜色
            g.setPaint(color);
            //设置字体
            g.setFont(font);
            //调用写文字方法
            row = drawString(g, font, text, x, y, maxWeight, fontheight, center, rate);
            g.dispose();
            //输出图片
            FileOutputStream out = new FileOutputStream(outPath);
            ImageIO.write(bimage, "png", out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return row;
    }

    /**
     * 向画布上写多行文字文字，自适应,默认是给定的图片
     *
     *   原图路径
     * @param text       要添加的文字
     * @param outPath    输出图片路径
     * @param font       字体
     * @param textHeight          坐标y
     * @param color      字体颜色
     * @param fontheight 字体高度
     * @param maxWeight  每行字体最大宽度
     * center     是否居中
     * rate       字体间距
     * @return int  写了几行字
     */
    public static int drawTextToImgByDefault(BufferedImage bimage,
                                    String text,
                                    String outPath,
                                    Font font,
                                    int textHeight,
                                    Color color,
                                    int maxWeight,
                                    int fontheight
                                     ) {
        int row = 0;
        try {
            //图片的高
            int imgHerght = bimage.getHeight();
            //图片的宽
            int imgWidth = bimage.getWidth();
            //居中显示
            int x = (imgWidth - maxWeight) / 2;
            int y=textHeight;
            //得到2d画笔对象
            Graphics2D g = bimage.createGraphics();
            //设置填充颜色
            g.setPaint(color);
            //设置字体
            g.setFont(font);
            //调用写文字方法
            row = drawString(g, font, text, x, y, maxWeight, fontheight, true, 1);
            g.dispose();
            //输出图片
            FileOutputStream out = new FileOutputStream(outPath);
            ImageIO.write(bimage, "png", out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return row;
    }

    /**
     * 向画布上写多行文字文字，自动居中
     *
     * @param filePath   原图路径
     * @param text       要添加的文字
     * @param outPath    输出图片路径
     * @param font       字体
     * @param textHeight          坐标y
     * @param color      字体颜色
     * @param fontheight 字体高度
     * @param maxWeight  每行字体最大宽度
     * @param center     是否居中
     * @param rate       字体间距
     * @return int  写了几行字
     */
    public static int addTextInImgByCenter(String filePath,
                                    String text,
                                    String outPath,
                                    Font font,
                                    int textHeight,
                                    Color color,
                                    int maxWeight,
                                    int fontheight,
                                    boolean center,
                                    double rate) {
        int row = 0;
        try {
            //图片加载到缓冲区
            BufferedImage bimage = imageIoRead(filePath);
            //图片的高
            int imgHerght = bimage.getHeight();
            //图片的宽
            int imgWidth = bimage.getWidth();
            //居中显示
            int x = (imgWidth - maxWeight) / 2;
            int y=(imgHerght-textHeight)/2;
            //得到2d画笔对象
            Graphics2D g = bimage.createGraphics();
            //设置填充颜色
            g.setPaint(color);
            //设置字体
            g.setFont(font);
            //调用写文字方法
            row = drawString(g, font, text, x, y, maxWeight, fontheight, center, rate);
            g.dispose();
            //输出图片
            FileOutputStream out = new FileOutputStream(outPath);
            ImageIO.write(bimage, "png", out);
            out.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return row;
    }

    /**
     * 写文字
     *
     * @param g        2d画笔对象
     * @param font     字体
     * @param text     要添加的文字
     * @param x        坐标X
     * @param y        坐标y
     * @param maxWidth 每行字体最大宽度
     * @param height   字体高度
     * @param center   是否居中
     * @param rate     字体间距
     * @return int 写了几行字
     */
    public static int drawString(Graphics2D g,
                                 Font font,
                                 String text,
                                 int x,
                                 int y,
                                 int maxWidth,
                                 int height,
                                 boolean center,
                                 double rate) {
        int row = 1;
        JLabel label = new JLabel(text);
        label.setFont(font);
        FontMetrics metrics = label.getFontMetrics(label.getFont());
        int textH = height;
        int textW = metrics.stringWidth(label.getText()); //字符串的宽
        String tempText = text;
        //如果字符串长度大于最大宽度，执行循环
        while (textW > maxWidth) {
            int n = textW / maxWidth;
            int subPos = tempText.length() / n;
            String drawText = tempText.substring(0, subPos);
            int subTxtW = metrics.stringWidth(drawText);
            while (subTxtW > maxWidth) {
                subPos--;
                drawText = tempText.substring(0, subPos);
                subTxtW = metrics.stringWidth(drawText);
            }
            //g.drawString(drawText, x, y);  //不调整字体间距
            MyDrawString(drawText, x, y, rate, g);
            y += textH;
            textW = textW - subTxtW;
            tempText = tempText.substring(subPos);
            row++;
        }
        //居中
        if (center) {
            x = x + (maxWidth - textW) / 2;
        }
        //g.drawString(tempText, x, y);  //不调整字体间距
        MyDrawString(tempText, x, y, rate, g);
        return row;
    }

    /**
     * 一个字一个字写，控制字体间距
     *
     * @param str  要添加的文字
     * @param x    坐标x
     * @param y    坐标y
     * @param rate 字体间距
     * @param g    画笔
     */
    public static void MyDrawString(String str, int x, int y, double rate, Graphics2D g) {
        String tempStr = "";
        int orgStringWight = g.getFontMetrics().stringWidth(str);
        int orgStringLength = str.length();
        int tempx = x;
        int tempy = y;
        while (str.length() > 0) {
            tempStr = str.substring(0, 1);
            str = str.substring(1, str.length());
            g.drawString(tempStr, tempx, tempy);
            tempx = (int) (tempx + (double) orgStringWight / (double) orgStringLength * rate);
        }
    }

    /**
     * opencv实现图片旋转
     *
     * @param splitImage
     * @param angle
     * @return
     */
    public static Mat rotate3(Mat splitImage, double angle) {
        double thera = angle * Math.PI / 180;
        double a = Math.sin(thera);
        double b = Math.cos(thera);

        int wsrc = splitImage.width();
        int hsrc = splitImage.height();

        int wdst = (int) (hsrc * Math.abs(a) + wsrc * Math.abs(b));
        int hdst = (int) (wsrc * Math.abs(a) + hsrc * Math.abs(b));
        Mat imgDst = new Mat(hdst, wdst, splitImage.type());

        Point pt = new Point(splitImage.cols() / 2, splitImage.rows() / 2);
        // 获取仿射变换矩阵
        Mat affineTrans = Imgproc.getRotationMatrix2D(pt, angle, 1.0);

        System.out.println(affineTrans.dump());
        // 改变变换矩阵第三列的值
        affineTrans.put(0, 2, affineTrans.get(0, 2)[0] + (wdst - wsrc) / 2);
        affineTrans.put(1, 2, affineTrans.get(1, 2)[0] + (hdst - hsrc) / 2);

        Imgproc.warpAffine(splitImage, imgDst, affineTrans, imgDst.size(),
                Imgproc.INTER_CUBIC | Imgproc.WARP_FILL_OUTLIERS);
        return imgDst;
    }

    /**
     * 普通方法图像旋转
     *
     * @param src
     * @param angel
     * @return
     */
    public static BufferedImage rotate(Image src, double angel) {
        int src_width = src.getWidth(null);
        int src_height = src.getHeight(null);
        // calculate the new image size
        Rectangle rect_des = CalcRotatedSize(new Rectangle(new Dimension(
                src_width, src_height)), angel);

        BufferedImage res = null;
        res = new BufferedImage(rect_des.width, rect_des.height,
                BufferedImage.TYPE_3BYTE_BGR);
        Graphics2D g2 = res.createGraphics();
        // transform
        g2.translate((rect_des.width - src_width) / 2,
                (rect_des.height - src_height) / 2);
        g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2);

        g2.drawImage(src, null, null);
        return res;
    }

    public static Rectangle CalcRotatedSize(Rectangle src, double angel) {
        // if angel is greater than 90 degree, we need to do some conversion
        if (angel >= 90) {
            if (angel / 90 % 2 == 1) {
                int temp = src.height;
                src.height = src.width;
                src.width = temp;
            }
            angel = angel % 90;
        }

        double r = Math.sqrt(src.height * src.height + src.width * src.width) / 2;
        double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r;
        double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2;
        double angel_dalta_width = Math.atan((double) src.height / src.width);
        double angel_dalta_height = Math.atan((double) src.width / src.height);

        int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_width));
        len_dalta_width = len_dalta_width > 0 ? len_dalta_width : -len_dalta_width;

        int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha
                - angel_dalta_height));
        len_dalta_height = len_dalta_height > 0 ? len_dalta_height : -len_dalta_height;

        int des_width = src.width + len_dalta_width * 2;
        int des_height = src.height + len_dalta_height * 2;
        des_width = des_width > 0 ? des_width : -des_width;
        des_height = des_height > 0 ? des_height : -des_height;
        return new java.awt.Rectangle(new Dimension(des_width, des_height));
    }

    /**
     * 提高图片清晰度
     *
     * @throws Exception
     */
    public static void HDImage(String sourcePath, String outPath) throws Exception {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        Mat source = Imgcodecs.imread(sourcePath,
                Imgcodecs.IMWRITE_PNG_STRATEGY_FIXED);//设置读取的格式
        Mat destination = new Mat(source.rows(), source.cols(), source.type());
        Imgproc.GaussianBlur(source, destination, new Size(0, 0), 10);
        Core.addWeighted(source, 1.5, destination, -0.5, 0, destination);
        Imgcodecs.imwrite(outPath, destination);
    }

    /**
     * 提高图片像素
     *
     * @throws Exception
     */
    public static void changePixel(String sourcePath, String outPath) throws Exception {
        File file = new File(sourcePath);
        BufferedImage img = ImageIO.read(file);

        for (int x = 0; x < img.getWidth(); x++) {
            for (int y = 0; y < img.getHeight(); y++) {
                int rgb = img.getRGB(x, y);
                Color color = new Color(rgb);
                int r = color.getRed();
                int g = color.getGreen();
                int b = color.getBlue();

                int c = r + g + b;
                c = c / 3;

                Color newColor = new Color(c, c, c);
                img.setRGB(x, y, newColor.getRGB());
            }
        }

        System.out.println(img.getWidth());

        ImageIO.write(img, "bmp", new File(outPath));
//
//        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
//        Mat source = Imgcodecs.imread(sourcePath,
//                Imgcodecs.IMWRITE_PNG_STRATEGY_FIXED);//设置读取的格式
//        Mat colorImg = new Mat(source.rows(), source.cols(), source.type());


        //					大小 500x500		            	8位无符号3通道			              r     g    b
//        Mat colorImg = new Mat(new Size(700, 600), CvType.CV_8UC3, new Scalar(200, 100, 150));
//        Mat colorImg_cp = colorImg.clone();    // 获取一份拷贝


//        int rows = source.rows();        //行数
//        int cols = source.cols();          //列数
//        int ch = source.channels();     //通道数 (灰度: 1, RGB: 3, etc.)
//        for (int i = 0; i < rows; i++) {
//            for (int j = 0; j < cols; j++) {
//                double[] data = source.get(i, j);    //读取像素值，并存储在double数组中
//                for (int k = 0; k < ch; k++)        //RGB值或灰度值
//                {
//                    data[k] = (i + j) % 255;      //对每个像素值（灰度值或RGB通道值，取值0~255）进行处理
//                }
//                source.put(i, j, data);         //把处理后的像素值写回到Mat
//            }
//        }
//        Imgcodecs.imwrite(outPath, source);

//        for (int j = 0; j < colorImg.rows(); j++) {
//            for (int k = 0; k < colorImg.cols(); k++) {
//                // 获取 坐标（j，k）的 三个通道的像素值
//                // 因为colorImg是一张三通道的图片，因此获取的数组长度为3
//                // 三种色彩的顺序为：b g r  蓝 绿 红
//                double[] a = colorImg.get(j, k);
////                a[0] = (j + k) % 255;    // 蓝色 b
////                a[1] = (j + k) % 255;    // 绿色 g
////                a[2] = 0;            // 红色 r
//                System.out.println(a[0]);
//                colorImg.put(j, k, a);    // 将数组a的值覆盖到 坐标（j，k）的像素
//            }
//        }
//        Imgcodecs.imwrite(outPath, colorImg);

//        HighGui.imshow("C:\\Users\\user\\Desktop\\cimg\\1.jpg", colorImg_cp);    // 窗口显示原图片
//        HighGui.imshow("C:\\Users\\user\\Desktop\\cimg\\2.jpg", colorImg);        // 窗口显示修改后图片
//
//        HighGui.waitKey();
//        HighGui.destroyAllWindows();


    }


    /**
     * This class will resize all the images in a given folder
     *
     * @author pankaj
     */


    public static void changePictureSize(String sourcePath, String outPath) throws Exception {
        Image img = null;
        BufferedImage tempJPG = null;
        File newFileJPG = null;

        img = ImageIO.read(new File(sourcePath));
        tempJPG = resizeImage(img, 1920, 1080);
        newFileJPG = new File(outPath);
        ImageIO.write(tempJPG, "bmp", newFileJPG);
    }

    /**
     * This function resize the image file and returns the BufferedImage object that can be saved to file system.
     */
    public static BufferedImage resizeImage(final Image image, int width, int height) {
        final BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        final Graphics2D graphics2D = bufferedImage.createGraphics();
        graphics2D.setComposite(AlphaComposite.Src);
        //below three lines are for RenderingHints for better image quality at cost of higher processing time
        graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        graphics2D.drawImage(image, 0, 0, width, height, null);
        graphics2D.dispose();
        return bufferedImage;
    }


}
